
namespace Patterns4Net.Tests.Core.AttributePatterns
{
    using System;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.Linq;
    using NUnit.Framework;
    using Patterns4Net.Core;
    using Patterns4Net.Core.AttributesPatterns;
    using Patterns4Net.Attributes;
    using Patterns4Net.Core.CecilExtensions;
    using Patterns4Net.Core.Patterns;

    [TestFixture]
    public class PatternCreatorsCompositionTest
    {
        [Test]
        public void ForAllPatternsAttributesThereIsPatternCreatorRegistered()
        {
            var patternAttributes = typeof(IPatternAttribute).Assembly.GetTypes()
                .Where(x => x.Namespace.StartsWith("Patterns4Net.Attributes.DesignPatterns"))
                .Where(x => x.GetInterfaces().Any(i => i.Equals(typeof(IPatternAttribute))) &&
                    x.GetInterfaces().None(i => i.Equals(typeof(IPattern))));
            var container = this.GetContainer();
            var imports = container.GetExportedValue<Imports>();

            foreach (var attribute in patternAttributes)
            {
                Assert.IsTrue(
                    imports.TypePatternCheckers.Any(x => x.Metadata.AttributeType == attribute),
                    string.Format("For attribute {0} there is no pattern creator.", attribute.Name));
            }
        }

        [Test]
        public void ForAllPatternsThereIsPatternAttribute()
        {
            var patterns = typeof(PatternBase).Assembly.GetTypes()
                .Where(x => x.BaseType == typeof(PatternBase));
            var patternAttributes = typeof(IPatternAttribute).Assembly.GetTypes()
                .Where(x => x.GetInterfaces().Any(i => i == typeof(IPatternAttribute)))
                .Where(x => x.GetInterfaces().None(i => i == typeof(IPattern)));

            foreach (var pattern in patterns)
            {
                Assert.IsTrue(
                    patternAttributes.Any(x => x.Name == pattern.Name + "Attribute"),
                    string.Format("For pattern {0} there is no attribute.", pattern.Name));
            }

            foreach (var patternAttribute in patternAttributes)
            {
                Assert.IsTrue(
                    patterns.Any(x => x.Name + "Attribute" == patternAttribute.Name),
                    string.Format("For pattern attribute {0} there is no pattern.", patternAttribute.Name));                
            }
        }

        private CompositionContainer GetContainer()
        {
            var mefCatalog = new AggregateCatalog(
                new AssemblyCatalog(typeof(PatternBase).Assembly),
                new AssemblyCatalog(this.GetType().Assembly));
            return new CompositionContainer(mefCatalog);
        }

        [Export]
        public class Imports
        {
            [ImportingConstructor]
            public Imports(
                [ImportMany]Lazy<ICreatePatternFromAttribute, PatternCreatorExportAttribute>[] typePatternCheckers)
            {
                this.TypePatternCheckers = typePatternCheckers;
            }

            public Lazy<ICreatePatternFromAttribute, PatternCreatorExportAttribute>[] TypePatternCheckers { get; set; }
        }
    }
}
